programming4us
           
 
 
Programming

Microsoft ASP.NET 3.5 : Writing HTTP Handlers (part 2) - An HTTP Handler for Quick Data Reports

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
5/17/2012 3:51:34 PM

An HTTP Handler for Quick Data Reports

With their relatively simple programming model, HTTP handlers give you a means of interacting with the low-level request and response services of IIS. In the previous example, we returned only constant text and made no use of the request information. In the next example, we’ll configure the handler to intercept and process only requests of a particular type and generate the output based on the contents of the requested resource.

The idea is to build an HTTP handler for custom .sqlx resources. A SQLX file is an XML document that expresses the statements for one or more SQL queries. The handler grabs the information about the query, executes it, and finally returns the result set formatted as a grid. Figure 2 shows the expected outcome.

Figure 2. A custom HTTP handler in action.

To start, let’s examine the source code for the IHttpHandler class.

Warning

Take this example for what it really is—merely a way to process a custom XML file with a custom extension doing something more significant than outputting a “hello world” message. Do not take this handler as a realistic prototype for exposing your Microsoft SQL Server databases over the Web.


Building a Query Manager Tool

The HTTP handler should get into the game whenever the user requests an .sqlx resource. Assume for now that the system knows how to deal with such a weird extension, and focus on what’s needed to execute the query and pack the results into a grid. To execute the query, at a minimum, we need the connection string and the command text. The following text illustrates the typical contents of an .sqlx file:

<queries>
  <query connString="DATABASE=northwind;SERVER=localhost;UID...;">
    SELECT firstname, lastname, country FROM employees
  </query>
  <query connString="DATABASE=northwind;SERVER=localhost;UID=...;">
    SELECT companyname FROM customers WHERE country='Italy'
  </query>
</queries>

The XML document is formed by a collection of <query> nodes, each containing an attribute for the connection string and the text of the query.

The ProcessRequest method extracts this information before it can proceed with executing the query and generating the output:

class SqlxData
{
    public string ConnectionString;
    public string QueryText;
}

public class QueryHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        // Parses the SQLX file
        SqlxData[] data = ParseFile(context);

        // Create the output as HTML
        StringCollection htmlColl = CreateOutput(data);

        // Output the data
        context.Response.Write("<html><head><title>");
        context.Response.Write("QueryHandler Output");
        context.Response.Write("</title></head><body>");
        foreach (string html in htmlColl)
        {
            context.Response.Write(html);
            context.Response.Write("<hr />");
        }
        context.Response.Write("</body></html>");
}
    // Override the IsReusable property
    public bool IsReusable
    {
        get { return true; }
    }

    ...
}


					  

The ParseFile helper function parses the source code of the .sqlx file and creates an instance of the SqlxData class for each query found:

private SqlxData[] ParseFile(HttpContext context)
{
   XmlDocument doc = new XmlDocument();
   string filePath = context.Request.Path;
   using (Stream fileStream = VirtualPathProvider.OpenFile(filePath))  {
       doc.Load(fileStream);
   }

   // Visit the <mapping> nodes
   XmlNodeList mappings = doc.SelectNodes("queries/query");
   SqlxData[] descriptors = new SqlxData[mappings.Count];
   for (int i=0; i < descriptors.Length; i++)
   {
       XmlNode mapping = mappings[i];
       SqlxData query = new SqlxData();
       descriptors[i] = query;

       try {
           query.ConnectionString =
              mapping.Attributes["connString"].Value;
           query.QueryText = mapping.InnerText;
       }
       catch {
           context.Response.Write("Error parsing the input file.");
           descriptors = new SqlxData[0];
           break;
       }
   }
   return descriptors;
}


					  

The SqlxData internal class groups the connection string and the command text. The information is passed to the CreateOutput function, which will actually execute the query and generate the grid:

private StringCollection CreateOutput(SqlxData[] descriptors)
{
    StringCollection coll = new StringCollection();

    foreach (SqlxData data in descriptors)
    {
        // Run the query
        DataTable dt = new DataTable();
        SqlDataAdapter adapter = new SqlDataAdapter(data.QueryText,
            data.ConnectionString);
        adapter.Fill(dt);


        // Error handling
        ...

        // Prepare the grid
        DataGrid grid = new DataGrid();
        grid.DataSource = dt;
        grid.DataBind();

        // Get the HTML
        string html = Utils.RenderControlAsString(grid);
        coll.Add(html);
    }
    return coll;
}


					  

After executing the query, the method populates a dynamically created DataGrid control. In ASP.NET pages, the DataGrid control, like any other control, is rendered to HTML. However, this happens through the care of the special HTTP handler that manages .aspx resources. For .sqlx resources, we need to provide that functionality ourselves. Obtaining the HTML for a Web control is as easy as calling the RenderControl method on an HTML text writer object. This is just what the helper method RenderControlAsString does:

static class Utils
{
    public static string RenderControlAsString(Control ctl)
    {
        StringWriter sw = new StringWriter();
        HtmlTextWriter writer = new HtmlTextWriter(sw);
        ctl.RenderControl(writer);
        return sw.ToString();

    }
}

Note

An HTTP handler that needs to access session-state values must implement the IRequiresSessionState interface. Like INamingContainer, it’s a marker interface and requires no method implementation. Note that the IRequiresSessionState interface indicates that the HTTP handler requires read and write access to the session state. If read-only access is needed, use the IReadOnlySessionState interface instead.


Registering the Handler

An HTTP handler is a class and must be compiled to an assembly before you can use it. The assembly must be deployed to the Bin directory of the application. If you plan to make this handler available to all applications, you can copy it to the global assembly cache (GAC). The next step is registering the handler with an individual application or with all the applications running on the Web server. You register the handler in the configuration file:

<system.web>
  <httpHandlers>
    <add verb="*"
      path="*.sqlx"
      type= "Core35.Components.QueryHandler,Core35Lib" />
  </httpHandlers>
</system.web>

You add the new handler to the <httpHandlers> section of the local or global web.config file. The section supports three actions: <add>, <remove>, and <clear>. You use <add> to add a new HTTP handler to the scope of the .config file. You use <remove> to remove a particular handler. Finally, you use <clear> to get rid of all the registered handlers. To add a new handler, you need to set three attributes—verb, path, and type—as shown in Table 2.

Table 2. Attributes Needed to Register an HTTP Handler
AttributeDescription
VerbIndicates the list of the supported HTTP verbs—for example, GET, PUT, and POST. The wildcard character (*) is an acceptable value and denotes all verbs.
PathA wildcard string, or a single URL, that indicates the resources the handler will work on—for example, *.aspx.
TypeSpecifies a comma-separated class/assembly combination. ASP.NET searches for the assembly DLL first in the application’s private Bin directory and then in the system global assembly cache.

These attributes are mandatory. An optional attribute is also supported—validate. When validate is set to false, ASP.NET delays as much as possible loading the assembly with the HTTP handler. In other words, the assembly will be loaded only when a request for it arrives. ASP.NET will not try to preload the assembly, thus catching any error or problem with it.

So far, you have correctly deployed and registered the HTTP handler, but if you try invoking an .sqlx resource, the results you produce are not what you’d expect. The problem lies in the fact that so far you configured ASP.NET to handle only .sqlx resources, but IIS still doesn’t know anything about them!

A request for an .sqlx resource is handled by IIS before it is handed to the ASP.NET ISAPI extension. If you don’t register some ISAPI extension to handle ..sqlx resource requests, IIS will treat each request as a request for a static resource and serve the request by sending back the source code of the .sqlx file. The extra step required is registering the .sqlx extension with the IIS 6.0 metabase such that requests for .sqlx resources are handed off to ASP.NET, as shown in Figure 3.

Figure 3. Registering the .sqlx extension with the IIS 6.0 metabase.


The dialog box in the figure is obtained by clicking on the properties of the application in the IIS 6.0 manager and then the configuration of the site. To involve the HTTP handler, you must choose aspnet_isapi.dll as the ISAPI extension. In this way, all .sqlx requests are handed out to ASP.NET and processed through the specified handler. Make sure you select aspnet_isapi.dll from the folder of the ASP.NET version you plan to use.

Caution

In Microsoft Visual Studio, if you test a sample .sqlx resource using the local embedded Web server, nothing happens that forces you to register the .sqlx resource with IIS. This is just the point, though. You’re not using IIS! In other words, if you use the local Web server, you have no need to touch IIS; you do need to register any custom resource you plan to use with IIS before you get to production.


Registering the Handler with IIS 7.0

If you run IIS 7.0, you don’t strictly need to change anything through the IIS Manager. You can add a new section to the web.config file and specify the HTTP handler also for static resources that would otherwise be served directly by IIS. Here’s what you need to enter:

<system.webServer>
    <add verb="*"
        path="*.sqlx"
        type="Core35.Components.QueryHandler, Core35Lib" />
</system.webServer>

The new section is a direct child of the root tag <configuration>. Without this setting, IIS can’t recognize the page and won’t serve it up. The configuration script instructs IIS 7.0 to forward any *.sqlx requests to your application, which knows how to deal with it.

Other -----------------
- Microsoft ASP.NET 3.5 : HTTP Handlers and Modules - Quick Overview of the IIS Extensibility API
- Programming WCF Services : Queued Services - The HTTP Bridge
- Microsoft ASP.NET 4 : Ajax - Extender Controls (part 2) - A Modal Pop-up Dialog-Style Component
- Microsoft ASP.NET 4 : Ajax - Extender Controls (part 1) - The AutoComplete Extender
- Mobile Handheld Devices : DATA SYNCHRONIZATION
- Mobile Handheld Devices : MEMORY, STORAGE AND BATTERIES
- LINQ to Objects : How to Return Elements When the Result Is a Sequence (Select Many)
- LINQ to Objects : How to Change the Return Type (Select Projection)
- A Technical Overview of the Mobile Web : OTHER MOBILE TECHNOLOGIES
- A Technical Overview of the Mobile Web : THE MOBILE NETWORK
- Programming WCF Services : The Response Service (part 4) - Transactions
- Programming WCF Services : The Response Service (part 3) - Queued Service-Side Programming & Response Service-Side Programming
- Programming WCF Services : The Response Service (part 2) - Client-Side Programming
- Programming WCF Services : The Response Service (part 1) - Designing a Response Service Contract
- Programming WCF Services : Queued Versus Connected Calls - Requiring Queuing
- Programming WCF Services : Queued Services - Playback Failures
- DotNetNuke Skinning : Package and Deploy
- Unit Testing in Visual Studio 2010 (part 2) - Running a battery of tests
- Unit Testing in Visual Studio 2010 (part 1) - Creating unit tests
- Microsoft ASP.NET 3.5 : AJAX-Enabled Web Services - Remote Calls via Page Methods
 
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
programming4us programming4us